package com.jumi.microservice.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jumi.microservice.common.constant.DelFlag;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.common.page.TableDataInfo;
import com.jumi.microservice.common.utils.DateUtil;
import com.jumi.microservice.common.utils.EnumUtil;
import com.jumi.microservice.config.UserCashConfig;
import com.jumi.microservice.constant.UserCashStatusEnum;
import com.jumi.microservice.constant.usercash.CashStatusApiEnum;
import com.jumi.microservice.constant.usercash.CashTypeEnum;
import com.jumi.microservice.dto.reponse.UserCashExternalResponse;
import com.jumi.microservice.dto.usercash.TypeListResponse;
import com.jumi.microservice.dto.usercash.api.*;
import com.jumi.microservice.dto.wallet.api.WalletInOrOutRequest;
import com.jumi.microservice.entity.UserCash;
import com.jumi.microservice.enumerate.WalletTypeEnum;
import com.jumi.microservice.exception.UserCashExceptionEnum;
import com.jumi.microservice.mapper.UserCashMapper;
import com.jumi.microservice.mapper.UserWalletMapper;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author Scw
 * @Date 2020-07-21 16:12
 */
@Service
public class UserCashService {
    @Resource
    private UserCashMapper userCashMapper;
    @Resource
    private UserCashConfig userCashConfig;
    @Resource
    private UserWalletMapper userWalletMapper;
    @DubboReference
    private IUserExternalService iUserExternalService;
    @DubboReference
    IWalletInOrOutService iWalletInOrOutService;
    @DubboReference
    private ICpsUserCashDubboService iCpsUserCashDubboService;

    /**
     * 提现列表
     */
    public TableDataInfo<UserCashApiListResponse> userCashList(UserCashApiListRequest userCashApiListRequest) {
        //获取当前用户ID
        Long userId = userCashApiListRequest.getUid();
        if (userId == null) {
            throw new BaseException(UserCashExceptionEnum.NO_LOGIN.getCode(), UserCashExceptionEnum.NO_LOGIN.getMessage());
        }
        QueryWrapper<UserCash> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", userId);
        queryWrapper.eq("del_flag", DelFlag.NORMAL);
        queryWrapper.orderByDesc("id");
        //申请时间
        //String nowYearMonth = DateUtil.getYear() + "-" + DateUtil.getMonth();
        if (userCashApiListRequest.getCreateTime() != null && !"".equals(userCashApiListRequest.getCreateTime())) {
            String nowYearMonth = userCashApiListRequest.getCreateTime();
            queryWrapper.ge("create_time", this.getFirstDayOfMonth(nowYearMonth));
            queryWrapper.le("create_time", this.getLastDayOfMonth(nowYearMonth));
        }
        IPage<UserCash> page = new Page<>(userCashApiListRequest.getPageNum(), userCashApiListRequest.getPageSize());
        page = userCashMapper.selectPage(page, queryWrapper);

        List<UserCash> userCashs = page.getRecords();

        List<UserCashApiListResponse> result = new ArrayList<>();

        for (UserCash userCash : userCashs) {
            UserCashApiListResponse userCashApiListResponse = new UserCashApiListResponse();
            BeanUtils.copyProperties(userCash, userCashApiListResponse);
            userCashApiListResponse.setUserCashId(userCash.getId());
            //提现账户类型对照
            CashTypeEnum cashTypeEnum = EnumUtil.getByCode(userCash.getCashType().intValue(), CashTypeEnum.class);
            if (cashTypeEnum != null) {
                userCashApiListResponse.setCashTypeStr(cashTypeEnum.getDesc());
            }
            //提现状态对照
            CashStatusApiEnum cashStatusApiEnum = EnumUtil.getByCode(userCash.getStatus().intValue(), CashStatusApiEnum.class);
            if (cashStatusApiEnum != null) {
                userCashApiListResponse.setStatusStr(cashStatusApiEnum.getDesc());
            }
            result.add(userCashApiListResponse);
        }
        TableDataInfo<UserCashApiListResponse> dataInfo = new TableDataInfo<>();
        dataInfo.setRows(result);
        dataInfo.setTotal(page.getTotal());
        return dataInfo;
    }

    /**
     * 提现相关限额
     */
    public AmountLimitResponse amountLimit(Long userId) {
        //获取当前用户ID
        if (userId == null) {
            throw new BaseException(UserCashExceptionEnum.NO_LOGIN.getCode(), UserCashExceptionEnum.NO_LOGIN.getMessage());
        }
        //本月提现金额总额上限额度
        BigDecimal upperBoundMoney = new BigDecimal(userCashConfig.getUpperBoundMoney());
        //最大提现金额
        BigDecimal maxWithdraw = new BigDecimal(userCashConfig.getMaxWithdraw());
        //最小提现金额
        BigDecimal minWithdraw = new BigDecimal(userCashConfig.getMinWithdraw());
        //本月已提现金额总额
        //BigDecimal totalAmountByMonth = this.getTotalAmountByMonth(userId);
        BigDecimal totalAmountByMonth = Integer.valueOf(userCashConfig.getSyncSwitchEnable()) == DelFlag.NORMAL ? this.getTotalAmountByMonth(userId) : this.getTotalAmountByMonth(userId).add(iCpsUserCashDubboService.getTotalAmountByMonth(userId));
        AmountLimitResponse amountLimitResponse = new AmountLimitResponse();
        amountLimitResponse.setUpperBoundMoney(upperBoundMoney);
        amountLimitResponse.setMaxWithdraw(maxWithdraw);
        amountLimitResponse.setMinWithdraw(minWithdraw);
        amountLimitResponse.setTotalAmountByMonth(totalAmountByMonth);
        return amountLimitResponse;
    }

    /**
     * 提现详情
     */
    public UserCashApiDetailResponse userCashDetail(UserCashApiDetailRequest userCashApiDetailRequest) {
        //获取当前用户ID
        Long userId = userCashApiDetailRequest.getUid();
        if (userId == null) {
            throw new BaseException(UserCashExceptionEnum.NO_LOGIN.getCode(), UserCashExceptionEnum.NO_LOGIN.getMessage());
        }
        //获取提现信息ID
        int userCashId = userCashApiDetailRequest.getUserCashId();
        //查询信息
        QueryWrapper<UserCash> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", userId);
        queryWrapper.eq("del_flag", DelFlag.NORMAL);
        queryWrapper.eq("id", userCashId);
        UserCash userCash = userCashMapper.selectOne(queryWrapper);
        if (userCash == null) {
            throw new BaseException(UserCashExceptionEnum.INFO_NO_EXIST.getCode(), UserCashExceptionEnum.INFO_NO_EXIST.getMessage());
        }
        //传递信息
        UserCashApiDetailResponse userCashApiDetailResponse = new UserCashApiDetailResponse();
        BeanUtils.copyProperties(userCash, userCashApiDetailResponse);
        //提现账户类型对照
        CashTypeEnum cashTypeEnum = EnumUtil.getByCode(userCash.getCashType().intValue(), CashTypeEnum.class);
        if (cashTypeEnum != null) {
            userCashApiDetailResponse.setCashTypeStr(cashTypeEnum.getDesc());
        }
        //提现状态对照
        CashStatusApiEnum cashStatusApiEnum = EnumUtil.getByCode(userCash.getStatus().intValue(), CashStatusApiEnum.class);
        if (cashStatusApiEnum != null) {
            userCashApiDetailResponse.setStatusStr(cashStatusApiEnum.getDesc());
        }
        userCashApiDetailResponse.setCheckRemark("");
        if (userCash.getStatus() == CashStatusApiEnum.STATUS_AUDIT_FAILED.getCode().byteValue()) {
            userCashApiDetailResponse.setCheckRemark(userCash.getCheckRemark());
        }
        userCashApiDetailResponse.setPayMsg("");
        //提现失败
        if (userCash.getStatus() == CashStatusApiEnum.STATUS_CASH_FAILED.getCode().byteValue()) {
            if (!"".equals(userCash.getPayStatusDetailMessage()) && null != userCash.getPayStatusDetailMessage()) {
                userCashApiDetailResponse.setPayMsg(userCash.getPayStatusDetailMessage());
            }
        }
        return userCashApiDetailResponse;
    }

    /**
     * 申请提现
     */
    @org.springframework.transaction.annotation.Transactional
    public Boolean addUserCash(UserCashApiAddRequest userCashApiAddRequest) {
        //提现开关：0-关闭 1-开启
        if (Integer.valueOf(userCashConfig.getSwitchEnable()) == DelFlag.NORMAL) {
            throw new BaseException(UserCashExceptionEnum.SWITCH_ENABLE_ZERO.getCode(), UserCashExceptionEnum.SWITCH_ENABLE_ZERO.getMessage());
        }
        //获取当前用户ID
        Long userId = userCashApiAddRequest.getUid();
        if (userId == null) {
            throw new BaseException(UserCashExceptionEnum.NO_LOGIN.getCode(), UserCashExceptionEnum.NO_LOGIN.getMessage());
        }
        /*
         * 根据用户ID，获取用户认证身份相关信息
         * 真实姓名、身份证号、银行卡号、支付宝帐号、用户等级、金牌推广商支付宝帐号
         * 实名认证状态、角色认证状态、 金牌推广商认证状态
         */
        UserCashExternalResponse userCashExternalResponse = iUserExternalService.getUserCashByUid(userId.intValue());
        // 获取用户认证身份相关信息
        if (userCashExternalResponse == null) {
            throw new BaseException(UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getCode(), UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getMessage());
        }
        // 真实姓名
        String trueName = userCashExternalResponse.getTrueName() == null ? "" : userCashExternalResponse.getTrueName();
        // 身份证号
        String idCard = userCashExternalResponse.getIdCard() == null ? "" : userCashExternalResponse.getIdCard();
        // 银行卡号
        String bankCard = userCashExternalResponse.getBankCard() == null ? "" : userCashExternalResponse.getBankCard();
        // 支付宝帐号
        String aliCode = userCashExternalResponse.getAliCode() == null ? "" : userCashExternalResponse.getAliCode();
        // 用户等级
        int userLevel = userCashExternalResponse.getUserLevel();
        // 金牌推广商支付宝帐号
        String goldAliCode = userCashExternalResponse.getGoldAliCode() == null ? "" : userCashExternalResponse.getGoldAliCode();
        // 实名认证状态
        int realStatus = userCashExternalResponse.getRealStatus();
        // 角色认证状态
        int identityStatus = userCashExternalResponse.getIdentityStatus();
        // 金牌推广商认证状态
        int goldStatus = userCashExternalResponse.getGoldStatus();

        //提现帐号
        String cashAccount;
        // 金牌推广商
        if (userLevel == UserCashStatusEnum.USER_ROLE_KING.getCode()) {
            // 实名认证状态、角色认证状态、金牌推广商认证状态
            if (identityStatus != UserCashStatusEnum.USER_STATUS_PASSED.getCode() || realStatus != UserCashStatusEnum.USER_STATUS_PASSED.getCode() || goldStatus != UserCashStatusEnum.USER_STATUS_PASSED.getCode()) {
                throw new BaseException(UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getCode(), UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getMessage());
            }
            // 提现类型：支付宝
            if (userCashApiAddRequest.getCashType() != UserCashStatusEnum.CASH_ALIPAY.getCode().intValue()) {
                throw new BaseException(UserCashExceptionEnum.NO_ALLOW_TYPE.getCode(), UserCashExceptionEnum.NO_ALLOW_TYPE.getMessage());
            }
            cashAccount = goldAliCode;
        } else {
            // 实名认证状态、角色认证状态
            if (identityStatus != UserCashStatusEnum.USER_STATUS_PASSED.getCode() || realStatus != UserCashStatusEnum.USER_STATUS_PASSED.getCode()) {
                throw new BaseException(UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getCode(), UserCashExceptionEnum.IDENTITY_NO_CERTIFICATION.getMessage());
            }
            //提现类型：支付宝/银行卡
            if (userCashApiAddRequest.getCashType() == UserCashStatusEnum.CASH_BANKCARD.getCode().intValue()) {
                if (bankCard == null || bankCard.length() == 0) {
                    throw new BaseException(UserCashExceptionEnum.NO_VERIFIED_BANKCARD.getCode(), UserCashExceptionEnum.NO_VERIFIED_BANKCARD.getMessage());
                }
                cashAccount = bankCard;
            } else if (userCashApiAddRequest.getCashType() == UserCashStatusEnum.CASH_ALIPAY.getCode().intValue()) {
                if (aliCode == null || aliCode.length() == 0) {
                    throw new BaseException(UserCashExceptionEnum.NO_VERIFIED_ALICODE.getCode(), UserCashExceptionEnum.NO_VERIFIED_ALICODE.getMessage());
                }
                cashAccount = aliCode;
            } else {
                throw new BaseException(UserCashExceptionEnum.NO_ALLOW_TYPE.getCode(), UserCashExceptionEnum.NO_ALLOW_TYPE.getMessage());
            }
        }
        //真实姓名
        if ("".equals(trueName)) {
            throw new BaseException(UserCashExceptionEnum.NO_VERIFIED_TRUENAME.getCode(), UserCashExceptionEnum.NO_VERIFIED_TRUENAME.getMessage());
        }
        //身份证号
        if ("".equals(idCard)) {
            throw new BaseException(UserCashExceptionEnum.NO_VERIFIED_IDCARD.getCode(), UserCashExceptionEnum.NO_VERIFIED_IDCARD.getMessage());
        }

        //最小提现金额
        BigDecimal minWithdraw = new BigDecimal(userCashConfig.getMinWithdraw());
        //最大提现金额
        BigDecimal maxWithdraw = new BigDecimal(userCashConfig.getMaxWithdraw());
        //本月提现金额总额上限额度
        BigDecimal upperBoundMoney = new BigDecimal(userCashConfig.getUpperBoundMoney());
        //本月已提现金额总额
        //BigDecimal totalAmountByMonth = this.getTotalAmountByMonth(userId);
        BigDecimal totalAmountByMonth = Integer.valueOf(userCashConfig.getSyncSwitchEnable()) == DelFlag.NORMAL ? this.getTotalAmountByMonth(userId) : this.getTotalAmountByMonth(userId).add(iCpsUserCashDubboService.getTotalAmountByMonth(userId));
        //可提现总金额
        BigDecimal totalAmount = userWalletMapper.getBalanceByUserId(userId);
        //赋值--申请提现金额
        BigDecimal amount = userCashApiAddRequest.getAmount();

        //判断提现金额是否 > 可提现总金额
        if (amount.compareTo(totalAmount) > 0) {
            throw new BaseException(UserCashExceptionEnum.CANWITHDRAW.getCode(), UserCashExceptionEnum.CANWITHDRAW.getMessage() + totalAmount + "元");
        }

        //判断提现金额是否 < 最低提现金额
        if (userCashApiAddRequest.getAmount().compareTo(minWithdraw) < 0) {
            throw new BaseException(UserCashExceptionEnum.MINWITHDRAW.getCode(), UserCashExceptionEnum.MINWITHDRAW.getMessage() + minWithdraw + "元");
        }

        //判断提现金额是否 > 最高提现金额
        if (userCashApiAddRequest.getAmount().compareTo(maxWithdraw) > 0) {
            throw new BaseException(UserCashExceptionEnum.MAXWITHDRAW.getCode(), UserCashExceptionEnum.MAXWITHDRAW.getMessage() + maxWithdraw + "元");
        }

        //本月提现金额总额上限额度 < 【本月已提现金额总额 + 申请提现金额】
        if (upperBoundMoney.compareTo(totalAmountByMonth.add(amount)) < 0) {
            throw new BaseException(UserCashExceptionEnum.UPPERBOUND.getCode(), UserCashExceptionEnum.UPPERBOUND.getMessage() + upperBoundMoney + "元");
        }

        //订单编号
        String orderNo = this.generateOrderSn();
        userCashApiAddRequest.setOrderNo(orderNo);
        //数据提交
        UserCash userCash = new UserCash();
        BeanUtils.copyProperties(userCashApiAddRequest, userCash);
        userCash.setCashAmount(userCashApiAddRequest.getAmount());
        userCash.setUid(userId);
        userCash.setCreateTime(new Date());
        userCash.setUpdateTime(new Date());
        userCash.setCashIdCard(idCard);
        userCash.setCashUserName(trueName);
        userCash.setCashAccount(cashAccount);
        int insertId = userCashMapper.insert(userCash);
        boolean isAdd = false;
        if (insertId > 0) {
            //添加收益
//            UserWallet userWallet = new UserWallet();
//            userWallet.setUserId(userId);
//            userWallet.setType(WalletTypeEnum.WITHDRAW_OUT.getCode());
//            userWallet.setAmount(userCashApiAddRequest.getAmount().negate());
//            userWallet.setRemark(WalletTypeEnum.WITHDRAW_OUT.getMsg());
//            userWallet.setOrderId(userCash.getId());
//            userWallet.setOrderNo(orderNo);
//            isAdd = userWalletMapper.insert(userWallet) > 0;
            WalletInOrOutRequest walletInOrOutRequest = new WalletInOrOutRequest();
            walletInOrOutRequest.setAmount(userCashApiAddRequest.getAmount());
            walletInOrOutRequest.setRemark(WalletTypeEnum.WITHDRAW_OUT.getMsg());
            walletInOrOutRequest.setUserId(userId);
            walletInOrOutRequest.setType(WalletTypeEnum.WITHDRAW_OUT.getCode());
            walletInOrOutRequest.setOrderNo(orderNo);
            walletInOrOutRequest.setOrderId(userCash.getId());
            isAdd = iWalletInOrOutService.walletOut(walletInOrOutRequest).getData();
        }
        return isAdd;
    }

    /**
     * 本月提现金额总额
     */
    private BigDecimal getTotalAmountByMonth(Long uid) {
        BigDecimal totalAmount = userCashMapper.getTotalAmountByMonth(uid);
        return totalAmount == null ? BigDecimal.ZERO : totalAmount;
    }

    /**
     * 生成订单号
     * 订单号部分使用long存储，
     * 取值范围应-9223372036854775808~9223372036854775807
     */
    private String generateOrderSn() {
        String time = DateUtil.getAllMSTime().substring(2);
        int randomInt = ThreadLocalRandom.current().nextInt(1000, 10000);
        return time + randomInt;
    }

    /**
     * 获取指定年月的第一天
     *
     * @param yearMonth
     * @return
     */
    public String getFirstDayOfMonth(String yearMonth) {
        int year = Integer.parseInt(yearMonth.split("-")[0]);  //年
        int month = Integer.parseInt(yearMonth.split("-")[1]); //月
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //获取某月最小天数
        int firstDay = cal.getMinimum(Calendar.DATE);
        //设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH, firstDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime()) + " 00:00:00";
    }

    /**
     * 获取指定年月的最后一天
     *
     * @param yearMonth
     * @return
     */
    public String getLastDayOfMonth(String yearMonth) {
        int year = Integer.parseInt(yearMonth.split("-")[0]);  //年
        int month = Integer.parseInt(yearMonth.split("-")[1]); //月
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, year);
        //设置月份
        cal.set(Calendar.MONTH, month - 1);
        //获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DATE);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime()) + " 23:59:59";
    }

    /**
     * 提现账户类型--对照字典
     */
    public List<TypeListResponse> getCashType() {
        List<TypeListResponse> result = new ArrayList<>();
        TypeListResponse typeListResponse1 = new TypeListResponse();
        typeListResponse1.setTypeId(CashTypeEnum.CASH_BANKCARD.getCode());
        typeListResponse1.setTypeName(CashTypeEnum.CASH_BANKCARD.getDesc());
        result.add(typeListResponse1);
        TypeListResponse typeListResponse2 = new TypeListResponse();
        typeListResponse2.setTypeId(CashTypeEnum.CASH_ALIPAY.getCode());
        typeListResponse2.setTypeName(CashTypeEnum.CASH_ALIPAY.getDesc());
        result.add(typeListResponse2);
        return result;
    }

    /**
     * 提现状态--对照字典
     */
    public List<TypeListResponse> getStatus() {
        List<TypeListResponse> result = new ArrayList<>();
        TypeListResponse typeListResponse1 = new TypeListResponse();
        typeListResponse1.setTypeId(CashStatusApiEnum.STATUS_APPLY.getCode());
        typeListResponse1.setTypeName(CashStatusApiEnum.STATUS_APPLY.getDesc());
        result.add(typeListResponse1);
        TypeListResponse typeListResponse2 = new TypeListResponse();
        typeListResponse2.setTypeId(CashStatusApiEnum.STATUS_AUDIT_PASSED.getCode());
        typeListResponse2.setTypeName(CashStatusApiEnum.STATUS_AUDIT_PASSED.getDesc());
        result.add(typeListResponse2);
        TypeListResponse typeListResponse3 = new TypeListResponse();
        typeListResponse3.setTypeId(CashStatusApiEnum.STATUS_AUDIT_FAILED.getCode());
        typeListResponse3.setTypeName(CashStatusApiEnum.STATUS_AUDIT_FAILED.getDesc());
        result.add(typeListResponse3);
        TypeListResponse typeListResponse4 = new TypeListResponse();
        typeListResponse4.setTypeId(CashStatusApiEnum.STATUS_CASH_ACCOUNT.getCode());
        typeListResponse4.setTypeName(CashStatusApiEnum.STATUS_CASH_ACCOUNT.getDesc());
        result.add(typeListResponse4);
        TypeListResponse typeListResponse5 = new TypeListResponse();
        typeListResponse5.setTypeId(CashStatusApiEnum.STATUS_CASH_FAILED.getCode());
        typeListResponse5.setTypeName(CashStatusApiEnum.STATUS_CASH_FAILED.getDesc());
        result.add(typeListResponse5);
        return result;
    }
}
